package cn.bandeqing.wechatminiapp.rpc.impl;

import cn.bandeqing.base.domain.CurrentWechatMiniAppUser;
import cn.bandeqing.base.resp.Resp;
import cn.bandeqing.config.service.IConfigService;
import cn.bandeqing.customerAddress.entity.CustomerAddress;
import cn.bandeqing.customerAddress.service.ICustomerAddressService;
import cn.bandeqing.frame.exception.CodeException;
import cn.bandeqing.order.entity.Order;
import cn.bandeqing.order.entity.OrderStatus;
import cn.bandeqing.order.req.OrderDetailReq;
import cn.bandeqing.order.resp.OrderDetailResp;
import cn.bandeqing.order.service.IOrderService;
import cn.bandeqing.productInventory.entity.ProductInventory;
import cn.bandeqing.productInventory.service.IProductInventoryService;
import cn.bandeqing.productInventoryRecord.entity.ChangeType;
import cn.bandeqing.productInventoryRecord.entity.ProductInventoryRecord;
import cn.bandeqing.productInventoryRecord.service.IProductInventoryRecordService;
import cn.bandeqing.store.rpc.IStoreRpc;
import cn.bandeqing.store.service.IStoreService;
import cn.bandeqing.stp.StpWechatMiniAppUtil;
import cn.bandeqing.wechatminiapp.req.*;
import cn.bandeqing.wechatminiapp.resp.*;
import cn.bandeqing.wechatminiapp.rpc.IWechatMiniAppRpc;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;
import io.github.linpeilie.Converter;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.date.DatePattern;
import org.dromara.hutool.core.date.DateTime;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.Collections;
import java.util.List;

import static cn.bandeqing.customerAddress.entity.table.CustomerAddressTableDef.CUSTOMER_ADDRESS;
import static cn.bandeqing.order.entity.table.OrderTableDef.ORDER;
import static cn.bandeqing.product.entity.table.ProductTableDef.PRODUCT;
import static cn.bandeqing.productInventory.entity.table.ProductInventoryTableDef.PRODUCT_INVENTORY;
import static cn.bandeqing.productInventoryRecord.entity.table.ProductInventoryRecordTableDef.PRODUCT_INVENTORY_RECORD;
import static cn.bandeqing.store.entity.table.StoreTableDef.STORE;

@Slf4j
@DubboService
public class WechatMiniAppRpcImpl implements IWechatMiniAppRpc {

    @Resource
    private IOrderService orderService;
    @Resource
    private IProductInventoryRecordService productInventoryRecordService;
    @Resource
    private ICustomerAddressService customerAddressService;
    @Resource
    private IStoreService storeService;
    @Resource
    private IProductInventoryService productInventoryService;
    @Resource
    private IConfigService configService;
    @Resource
    private Converter converter;

    @Override
    public Resp<List<OrderListResp>> list(OrderListReq req) {
        CurrentWechatMiniAppUser current = StpWechatMiniAppUtil.getCurrent();
        String customerPhoneNumber = current.getCustomerPhoneNumber();

        if (StrUtil.isBlank(customerPhoneNumber)) {
            return Resp.success(Collections.emptyList());
        }

        QueryWrapper qw = QueryWrapper.create()
                .select(ORDER.ALL_COLUMNS, PRODUCT.PRODUCT_MAIN_IMG, PRODUCT.MOVE_HOUSE)
                .leftJoin(PRODUCT).on(PRODUCT.PRODUCT_ID.eq(ORDER.PRODUCT_ID))
                .where(ORDER.CUSTOMER_PHONE.eq(customerPhoneNumber));
//                .where(ORDER.ORDER_STATUS.eq(req.getOrderStatus()));

        qw.limit((req.getPage() - 1) * req.getSize(), req.getSize()).orderBy(ORDER.ORDER_ID.desc());

        if (req.getType() == 0) {
            qw.where(ORDER.ORDER_STATUS.eq(req.getOrderStatus()));
        }

        if (StrUtil.isNotBlank(req.getDate())) {
            qw.where(ORDER.SERVICE_TIME.ge(req.getDate() + " 00:00:00"))
                    .where(ORDER.SERVICE_TIME.le(req.getDate() + " 23:59:59"));
        }

        List<OrderListResp> orderListResps = orderService.listAs(qw, OrderListResp.class);
        return Resp.success(orderListResps);
    }

    @Override
    public Resp<OrderDetailResp> detail(OrderDetailReq req) {
        OrderDetailResp detailResp = orderService.getOneAs(QueryWrapper.create()
                .select(ORDER.ALL_COLUMNS, PRODUCT.PRODUCT_MAIN_IMG, PRODUCT.PRODUCT_TYPE_ID, PRODUCT.PRODUCT_TYPE_NAME, PRODUCT.MOVE_HOUSE)
                .leftJoin(PRODUCT).on(PRODUCT.PRODUCT_ID.eq(ORDER.PRODUCT_ID))
                .where(ORDER.ORDER_ID.eq(req.getOrderId())), OrderDetailResp.class);

        List<OrderDetailResp.ProductDetail> productDetails = productInventoryRecordService.listAs(QueryWrapper.create()
                .where(PRODUCT_INVENTORY_RECORD.ORDER_ID.eq(req.getOrderId()))
                .where(PRODUCT_INVENTORY_RECORD.CHANGE_TYPE.eq(ChangeType.order_save)), OrderDetailResp.ProductDetail.class);

        detailResp.setProductDetails(productDetails);

        if (OrderStatus.wait_deposit.getValue().equals(detailResp.getOrderStatus())) {
            // 待支付定金
            Double payDeposit = ObjUtil.defaultIfNull(detailResp.getPayDeposit(), 0.0);
            Integer defaultDeposit = configService.keyInt("default_deposit", 100);
            Double shouldDeposit = detailResp.getShouldDeposit() == null ? defaultDeposit : detailResp.getShouldDeposit();
            if (payDeposit == 0 || payDeposit < shouldDeposit) {
                detailResp.setPayStatus(1);
                detailResp.setPayMoney(shouldDeposit - payDeposit);
            }

        } else if (OrderStatus.confirm.getValue().equals(detailResp.getOrderStatus())
                || OrderStatus.complete.getValue().equals(detailResp.getOrderStatus())) {
            // 已确认 || 已完成
            Double totalPrice = ObjUtil.defaultIfNull(detailResp.getTotalPrice(), 0.0);
            Double payDeposit = ObjUtil.defaultIfNull(detailResp.getPayDeposit(), 0.0);
            Double payFinalPayment = ObjUtil.defaultIfNull(detailResp.getPayFinalPayment(), 0.0);
            double payMoney = totalPrice - payDeposit - payFinalPayment;
            if (payMoney > 0) {
                detailResp.setPayStatus(2);
                detailResp.setPayMoney(payMoney);
            }
        }

        return Resp.success(detailResp);
    }

    @Override
    @Transactional
    public Resp<Void> appointment(OrderAppointmentReq req) {
        Order order = converter.convert(req, Order.class);
        if (StrUtil.isNotBlank(req.getServiceTimeStr())) {
            order.setServiceTime(new Timestamp(DateUtil.parse(req.getServiceTimeStr(), DatePattern.NORM_DATETIME_FORMAT).getTime()));
        }

        order.setOrderId(System.currentTimeMillis());
        order.setProductTotalPrice(req.getProductPrice());
        order.setTotalPrice(req.getProductPrice());
        order.setOrderStatus(OrderStatus.wait);

        ProductInventory pi = productInventoryService.getOne(QueryWrapper.create()
                .where(PRODUCT_INVENTORY.PRODUCT_ID.eq(req.getProductId()))
                .where(PRODUCT_INVENTORY.PRODUCT_SPECIFICATION_ID.eq(req.getProductSpecificationId()))
                .where(PRODUCT_INVENTORY.STORE_ID.eq(req.getStoreId())));
        Assert.notNull(pi, () -> new CodeException("当前产品店铺没有入库哦"));

        boolean save = orderService.save(order);
        Assert.isTrue(save, CodeException::new);

        Integer productInventory = pi.getProductInventory();
        Integer after = productInventory - 1;

        ProductInventory updatePi = ProductInventory.builder()
                .inventoryId(pi.getInventoryId())
                .productInventory(after)
                .build();
        boolean b = productInventoryService.updateById(updatePi);
        Assert.isTrue(b, CodeException::new);

        ProductInventoryRecord pir = ProductInventoryRecord.builder()
                .beforeInventory(pi.getProductInventory())
                .changeInventory(1)
                .afterInventory(after)
                .productId(req.getProductId())
                .productSpecificationId(req.getProductSpecificationId())
                .productSpecification(req.getProductSpecification())
                .productName(req.getProductName())
                .inventoryId(pi.getInventoryId())
                .storeId(req.getStoreId())
                .storeName(req.getStoreName())
                .changeType(ChangeType.order_save)
                .remark("客户微信小程序下单")
                .productPrice(req.getProductPrice())
                .productTotalPrice(req.getProductPrice())
                .orderId(order.getOrderId())
                .build();

        save = productInventoryRecordService.save(pir);
        Assert.isTrue(save, CodeException::new);

        return Resp.success();
    }

    @Override
    public Resp<List<CustomerAddressDetailResp>> addressList() {
        Long loginId = StpWechatMiniAppUtil.getLoginId();
        List<CustomerAddressDetailResp> customerAddressDetails = customerAddressService.listAs(QueryWrapper.create()
                .where(CUSTOMER_ADDRESS.CUSTOMER_ID.eq(loginId)), CustomerAddressDetailResp.class);

        return Resp.success(customerAddressDetails);
    }

    @Override
    public Resp<Void> customerAddressSaveOrUpdate(CustomerAddressSaveOrUpdateReq req) {
        CustomerAddress customerAddress = converter.convert(req, CustomerAddress.class);
        customerAddress.setCustomerId(StpWechatMiniAppUtil.getLoginId());

        boolean b = customerAddressService.saveOrUpdate(customerAddress);
        Assert.isTrue(b, CodeException::new);

        return Resp.success();
    }

    @Override
    public Resp<CustomerAddressDetailResp> customerAddressDetail(CustomerAddressDetailReq req) {

        CustomerAddressDetailResp customerAddressDetailResp = customerAddressService.getOneAs(QueryWrapper.create()
                .where(CUSTOMER_ADDRESS.ADDRESS_ID.eq(req.getAddressId())), CustomerAddressDetailResp.class);

        return Resp.success(customerAddressDetailResp);
    }

    @Override
    public Resp<List<StoreListResp>> storeList(StoreListReq req) {
        List<StoreListResp> storeListResps = storeService.listAs(QueryWrapper.create()
                .where(STORE.CITY_CODE.eq(req.getCityCode())), StoreListResp.class);
        return Resp.success(storeListResps);
    }

    @Override
    public Resp<StoreDetailResp> storeDetail(StoreDetailReq req) {
        StoreDetailResp detailResp = storeService.getOneAs(QueryWrapper.create()
                .where(STORE.STORE_ID.eq(req.getStoreId())), StoreDetailResp.class);
        return Resp.success(detailResp);
    }

    @Override
    public Resp<List<MonthOrderResp>> monthOrder(MonthOrderReq req) {
        CurrentWechatMiniAppUser current = StpWechatMiniAppUtil.getCurrent();

        if (StrUtil.isBlank(current.getCustomerPhoneNumber())) {
            return Resp.success(Collections.emptyList());
        }

        DateTime dateTime = DateUtil.parse(req.getYearMonth(), DatePattern.NORM_MONTH_FORMAT);
        int lastDayOfMonth = dateTime.getLastDayOfMonth();

        String start = req.getYearMonth() + "-01 00:00:00";
        String end = req.getYearMonth() + (lastDayOfMonth > 9 ? "-" + lastDayOfMonth + " 23:59:59" : "-0" + lastDayOfMonth + " 23:59:59");

        List<MonthOrderResp> monthOrderResps = orderService.listAs(QueryWrapper.create()
                .select("DATE_FORMAT(service_time, '%Y-%m-%d') AS service_time", "count(order_id) AS order_num")
                .where(ORDER.CUSTOMER_PHONE.eq(current.getCustomerPhoneNumber()))
                .where(ORDER.SERVICE_TIME.ge(start))
                .where(ORDER.SERVICE_TIME.le(end))
//                .where(ORDER.ORDER_STATUS.in(OrderStatus.confirm, OrderStatus.complete))
                .groupBy("DATE_FORMAT(service_time, '%Y-%m-%d')"), MonthOrderResp.class);

        return Resp.success(monthOrderResps);
    }

}
